package com.jzt.gateway.predicate;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.style.ToStringCreator;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;

import java.util.*;
import java.util.function.Predicate;

/**
 * 作者：lizw <br/>
 * 创建时间：2020/06/11 15:18 <br/>
 *
 * @see org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFactory
 */
@Component
@Slf4j
public class DomainRoutePredicateFactory extends AbstractRoutePredicateFactory<DomainRoutePredicateFactory.Config> {

    @Setter
    @Getter
    private PathMatcher pathMatcher = new AntPathMatcher(".");

    public DomainRoutePredicateFactory() {
        super(DomainRoutePredicateFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("patterns");
    }

    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST;
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                String host = exchange.getRequest().getURI().getHost();
                Optional<String> optionalPattern = config.getPatterns().stream().filter(pattern -> pathMatcher.match(pattern, host)).findFirst();
                if (optionalPattern.isPresent()) {
                    Map<String, String> variables = pathMatcher.extractUriTemplateVariables(optionalPattern.get(), host);
                    ServerWebExchangeUtils.putUriTemplateVariables(exchange, variables);
                    return true;
                }
                return false;
            }

            @Override
            public String toString() {
                return String.format("Hosts: %s", config.getPatterns());
            }
        };
    }

    public static class Config {
        private List<String> patterns = new ArrayList<>();

        public List<String> getPatterns() {
            return patterns;
        }

        public Config setPatterns(List<String> patterns) {
            this.patterns = patterns;
            return this;
        }

        @Override
        public String toString() {
            return new ToStringCreator(this).append("patterns", patterns).toString();
        }
    }
}
